﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using MiniGert;
using MiniGert.Transformation;

namespace MiniTest
{
  public partial class Form1 : Form
  {
    // Continous Collision Exmaple
    /*private LineSegment _segment = null;
    private Circle _circle = null;
    private Vector _circleDirection = null;*/

    //Ray reflection
    /*private LineSegment segment = null;
    private Ray ray = null;
    private Ray reflected = null;
    private MiniGert.Point target = new MiniGert.Point();
    private MiniGert.Point intersect = null;*/

    //Polygons
    private Polygon rect = Polygon.Rectangle(80, 60);
    private Polygon circle = Polygon.Circle(50, 36);
    private Polygon star = Polygon.Star(50, 30, 8);

    private bool debugDraw = false;

    [DllImport("Kernel32.dll")]
    private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

    [DllImport("Kernel32.dll")]
    private static extern bool QueryPerformanceFrequency(out long lpFrequency);

    public Form1()
    {
      InitializeComponent();
      this.ClientSize = new Size(800, 600);

      // Continous Collision Exmaple
      /*_segment = new LineSegment(this.ClientSize.Width / 2, this.ClientSize.Height / 2, this.ClientSize.Width / 2 + 100, this.ClientSize.Height / 2 - 40);
      _circle = new Circle(this.ClientSize.Width / 2 + 40, this.ClientSize.Height / 2 - 100, 20);

      _circleDirection = Vector.FromPoints(_circle.Center, _segment.MiddlePoint());
      _circleDirection.Normalize();
      _circleDirection.Scale(150);*/

      //Ray reflection
      /*segment = new LineSegment(300, 400, 500, 200);
      ray = new Ray();
      reflected = new Ray();*/
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
      Graphics gr = e.Graphics;
      gr.Clear(Color.White);
      gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

      MiniGert.Point center = new MiniGert.Point(100, 100);
      DrawPolygon(gr, rect, center);
      center.X += 150;
      DrawPolygon(gr, circle, center);
      center.X += 150;
      DrawPolygon(gr, star, center);
      
      //Ray reflection
      /*Graphics gr = e.Graphics;
      gr.Clear(Color.White);
      gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

      DrawLineSegment(gr, segment);

      DrawLine(gr, ray.Origin, target);

      DrawRay(gr, ray);

      if (intersect != null)
      {
        DrawRay(gr, reflected);
        DrawPoint(gr, intersect);
      }*/

      // Continous Collision Example
      /*Graphics gr = e.Graphics;
      gr.Clear(Color.White);
      gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

      DrawLineSegment(gr, _segment);
      DrawCircle(gr, _circle, Pens.Green);
      DrawVector(gr, _circleDirection, _circle.Center, 1.0f);

      Circle target = new Circle(MiniGert.Point.Transform(_circle.Center, _circleDirection, 1.0f), _circle.Radius);
      DrawCircle(gr, target, Pens.Silver);

      Vector segmentNormal = _segment.Normal();
      segmentNormal.Invert();
      MiniGert.Point rayStart = MiniGert.Point.Transform(_circle.Center, segmentNormal, _circle.Radius);
      Ray collisionRay = new Ray(rayStart, Vector.Normalize(_circleDirection), _circleDirection.Magnitude);
      MiniGert.Point collision = collisionRay.IntersectLineSegment(_segment);

      DrawLine(gr, _circle.Center, rayStart);
      DrawPoint(gr, rayStart);
      if (collision != null)
      {
        DrawLine(gr, rayStart, collision);
        DrawPoint(gr, collision);

        segmentNormal.Invert();
        Circle realCircle = new Circle(MiniGert.Point.Transform(collision, segmentNormal, _circle.Radius), _circle.Radius);
        DrawCircle(gr, realCircle, Pens.SteelBlue);

        float factor = MiniGert.Point.Distance(_circle.Center, target.Center) / MiniGert.Point.Distance(_circle.Center, realCircle.Center);
        gr.DrawString(factor.ToString(), SystemFonts.DefaultFont, Brushes.Black, 5, 5);
      }*/
    }

    private void Form1_MouseClick(object sender, MouseEventArgs e)
    {
      //Ray reflection
      /*if (e.Button == MouseButtons.Left)
      {
        ray.Origin.X = e.Location.X;
        ray.Origin.Y = e.Location.Y;
      }
      else if (e.Button == MouseButtons.Right)
      {
        target.X = e.Location.X;
        target.Y = e.Location.Y;
        Vector dir = Vector.FromPoints(ray.Origin, target);
        dir.Normalize();
        ray.Direction = dir;
        ray.Length = ray.Origin.DistanceTo(target);
      }

      intersect = ray.IntersectLineSegment(segment);
      if (intersect != null)
      {
        float distance = ray.Origin.DistanceTo(intersect);
        reflected.Direction = Vector.Reflect(ray.Direction, segment.Normal());
        reflected.Origin = intersect;
        reflected.Length = ray.Length - distance;
        ray.Length = distance;
      }

      this.Invalidate();*/

      // Continous Collision Exmaple
      /*_segment.Point2.X = e.Location.X;
      _segment.Point2.Y = e.Location.Y;
      this.Invalidate();*/
    }

    private void DrawPoint(Graphics gr, MiniGert.Point p)
    {
      gr.DrawRectangle(Pens.Red, p.X - 2, p.Y - 2, 4, 4);
    }

    private void DrawLine(Graphics gr, MiniGert.Point p1, MiniGert.Point p2)
    {
      gr.DrawLine(Pens.Silver, p1.X, p1.Y, p2.X, p2.Y);
    }

    private void DrawLineSegment(Graphics gr, LineSegment segment)
    {
      if (debugDraw)
      {
        MiniGert.Point middle = segment.MiddlePoint();
        MiniGert.Point point = MiniGert.Point.Transform(middle, segment.Normal(), 50);
        gr.DrawLine(Pens.Gold, middle.X, middle.Y, point.X, point.Y);
      }

      gr.DrawLine(Pens.Blue, segment.Point1.X, segment.Point1.Y, segment.Point2.X, segment.Point2.Y);
      DrawPoint(gr, segment.Point1);
      DrawPoint(gr, segment.Point2);
    }

    private void DrawVector(Graphics gr, Vector vec, MiniGert.Point start, float length)
    {
      MiniGert.Point point = MiniGert.Point.Transform(start, vec, length);
      gr.DrawLine(Pens.Magenta, start.X, start.Y, point.X, point.Y);
    }

    private void DrawCircle(Graphics gr, Circle circle, Pen color)
    {
      MiniGert.Rectangle bounds = circle.Bounds();

      if (debugDraw)
        gr.DrawRectangle(Pens.Gold, bounds.LeftTop.X, bounds.LeftTop.Y, bounds.Width, bounds.Height);

      gr.DrawEllipse(color, bounds.LeftTop.X, bounds.LeftTop.Y, bounds.Width, bounds.Height);
      DrawPoint(gr, circle.Center);
    }

    private void DrawRay(Graphics gr, Ray ray)
    {
      MiniGert.Point point = MiniGert.Point.Transform(ray.Origin, ray.Direction, ray.Length);
      gr.DrawLine(Pens.Green, ray.Origin.X, ray.Origin.Y, point.X, point.Y);
    }

    private void DrawPolygon(Graphics gr, Polygon poly, MiniGert.Point center)
    {
      for (int i = 1; i < poly.Vertices.Count; i++)
      {
        gr.DrawLine(Pens.Blue, poly.Vertices[i - 1].X + center.X, poly.Vertices[i - 1].Y + center.Y, poly.Vertices[i].X + center.X, poly.Vertices[i].Y + center.Y);
      }
      gr.DrawLine(Pens.Blue, poly.Vertices[poly.Vertices.Count - 1].X + center.X, poly.Vertices[poly.Vertices.Count - 1].Y + center.Y, poly.Vertices[0].X + center.X, poly.Vertices[0].Y + center.Y);
    }

  }
}
